//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#include "Platforms/Engine.Platforms.h"
#include "Base/Input/Input.h"

namespace Engine
{
namespace Base
{
	
/*
=================================================
	constructor
=================================================
*/
	Input::Input (const EngineSubSystemsRef ess) :
		BaseObject(ess), _lastTouchId(0), _numTouches(0),
		_keys( (uint8)EState::RELEASED )
	{
		ESS()->SetInput( this );

		ESS()->GetEventSystem()->AttachEventListener(
			DelegateBuilder::Create( InputPtr(this), &Input::_OnTouchEvent ),	ESystemEvent::RAW_TOUCH );

		ESS()->GetEventSystem()->AttachEventListener(
			DelegateBuilder::Create( InputPtr(this), &Input::_OnKeyEvent ),		ESystemEvent::RAW_KEY );
	}
	
/*
=================================================
	destructor
=================================================
*/
	Input::~Input ()
	{
		Ptr< EventSystem >	es = ESS()->GetEventSystem();

		if ( es.IsNotNull() )
		{
			ESS()->GetEventSystem()->DetachEventListener(
				DelegateBuilder::Create( InputPtr(this), &Input::_OnTouchEvent ),	ESystemEvent::RAW_TOUCH );

			ESS()->GetEventSystem()->DetachEventListener(
				DelegateBuilder::Create( InputPtr(this), &Input::_OnKeyEvent ),		ESystemEvent::RAW_KEY );

			ESS()->GetEventSystem()->Wait();
		}
		
		ESS()->SetInput( null );
	}
	
/*
=================================================
	_OnTouchEvent
=================================================
*/
	void Input::_OnTouchEvent (const SysEvent &ev)
	{
		_OnTouch( ev.rawTouch, ev.timestamp );
	}
	
/*
=================================================
	_OnKeyEvent
=================================================
*/
	void Input::_OnKeyEvent (const SysEvent &ev)
	{
		_OnKey( ev.rawKey, ev.timestamp );
	}
	
/*
=================================================
	_OnTouch
=================================================
*/
	void Input::_OnTouch (const SysEvent::RawTouch &ev, time_t timestamp)
	{
		_lastTouchId = ev.id;

		Touch &	touch = _touches[ _lastTouchId ];

		const ivec2	pos			= ivec2( int(ev.x), int(ev.y) );

		if ( EnumCmp( touch.state, EState::UP ) and ev.pressed )
		{
			touch.startPos	= pos;
			touch.pos		= pos;	// for zero delta
			touch.time		= timestamp;
		}

		uint8	state	 = ev.pressed ? EState::DOWN : EState::UP;

		touch.active	 = true;
		touch.delta		+= pos - touch.pos;
		touch.pos		 = pos;
		touch.motion	 = ev.pressed and ev.motion;
		touch.state		 = EnumCmp( touch.state, state ) ? (touch.state | state) : state;
		touch.pressure	 = ev.pressure;

		_numTouches = Max<uint>( _numTouches, _lastTouchId+1 );
	}
	
/*
=================================================
	_OnKey
=================================================
*/
	void Input::_OnKey (const SysEvent::RawKey &ev, time_t timestamp)
	{
		_keys[ ev.code ] = ev.pressed ? EState::DOWN : EState::UP;
	}
	
/*
=================================================
	PreUpdate
=================================================
*/
	void Input::PreUpdate ()
	{
		// TODO:
		// - detect zooming and rotating
		// - motion tracker

	}
	
/*
=================================================
	PostUpdate
=================================================
*/
	void Input::PostUpdate ()
	{
		_numTouches = 0;
		_lastTouchId = 0;

		FOR( i, _touches )
		{
			_touches[i].PostUpdate();
		}
	}


}	// Base
}	// Engine